/**
 * 
 */
package com.wolfking.back.core.aspect;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.google.common.collect.Sets;
import com.wolfking.back.core.annotation.ssoauth.Sign;
import com.wolfking.back.core.bean.User;
import com.wolfking.back.core.config.SsoConfig;
import com.wolfking.back.core.exception.SignException;
import com.wolfking.back.core.service.SsoUserService;

/**
 * 
 * <P>
 * 
 * @author wolfking@赵伟伟
 * @mail zww199009@163.com
 * @创作日期 2017年4月19日下午3:05:10
 * @版权 归wolfking所有
 */
@Aspect
@Configuration
@EnableConfigurationProperties(SsoConfig.class)
public class SignAspect {

	private Logger logger = LoggerFactory.getLogger(SignAspect.class);

	@Autowired
	private SsoConfig ssoConfig;
	@Autowired
	private SsoUserService ssoUserService;

	@Around("@annotation(sign)")
	public Object signOnMethod(ProceedingJoinPoint pjp, Sign sign) throws Throwable {
		return sign(pjp, sign);
	}

	@Around("@within(sign)")
	public Object signOnBean(ProceedingJoinPoint pjp, Sign sign) throws Throwable {
		return sign(pjp, sign);
	}

	/**
	 * 类上是否有@Controller和@RestController注解
	 * <P>
	 * 方法和类上是否有@RequestMapping注解
	 * 
	 * @param pjp
	 * @param sign
	 * @return
	 * @throws Throwable
	 */
	private Object sign(ProceedingJoinPoint pjp, Sign sign) throws Throwable {
		Object[] args = pjp.getArgs();
		if (ssoConfig.isEnabled()) {

			Signature signature = pjp.getSignature();
			MethodSignature methodSignature = (MethodSignature) signature;
			Method method = methodSignature.getMethod();
			Class<?> clazz = pjp.getTarget().getClass();
			if (clazz.getAnnotation(Controller.class) != null || clazz.getAnnotation(RestController.class) != null) {
				RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
				if (requestMapping == null)
					requestMapping = method.getAnnotation(RequestMapping.class);
				if (requestMapping != null) {
					logger.debug("进行sign登录校验");
					User user = ssoUserService.getUser();
					if (user == null)
						throw new SignException();
					logger.info("@sign校验通过");
					Class<?>[] classes = method.getParameterTypes();
					for (int i = classes.length - 1; i >= 0; i--)
						if (User.class.equals(classes[i])) {
							args[i] = user;
							break;
						}
					Set<String> codeSet = Sets.newHashSet();
					if (StringUtils.isNotEmpty(sign.code())) {
						codeSet = ssoUserService.getUserAuthCodes(user.getId());
						String code = sign.code();
						if (!codeSet.contains(code))
							throw new SignException(code);
					}
					// 添加freemarker的权限配置
					for (int i = 0; i < args.length; i++) {
						// 设置权限校验码
						if (args[i] instanceof Model && !(args[i] instanceof RedirectAttributes)) {
							if (codeSet.isEmpty())
								codeSet = ssoUserService.getUserAuthCodes(user.getId());
							Model.class.cast(args[i]).addAttribute("permissionCodes", codeSet);
							break;
						}
						if (args[i] instanceof ModelAndView) {
							if (codeSet.isEmpty())
								codeSet = ssoUserService.getUserAuthCodes(user.getId());
							ModelAndView.class.cast(args[i]).addObject("permissionCodes", codeSet);
							break;
						}
					}
					// 返回的ModelAndView 里面添加权限的标志
					Object obj = pjp.proceed(args);
					if (obj instanceof ModelAndView) {
						ModelAndView modelAndView = ModelAndView.class.cast(obj);
						if (modelAndView.getModelMap().containsKey("permissionCodes"))
							logger.info("modelAndview already has the permissionCodes propertity");
						else {
							Set<String> set = new HashSet<>();
							modelAndView.addObject("permissionCodes", set);
						}
					}
					return obj;
				} else
					logger.warn("不是合法的@Sign注解使用");
			} else
				logger.warn("不是合法的@Sign注解使用");
		}
		return pjp.proceed(args);
	}
}
